#include "API.h"

#include "math.h"

extern double accurateResultAt (double x, double t);

double firstDifference(double previous, double next) 
{
	return (next - previous) / (2.0 * Constant::H);
}

double secondDifference(double previous, double current, double next) 
{	
	return (previous - 2.0 * current + next) / (Constant::H * Constant::H);
}
double calculateNextLayerPoint(double previous, double current, double next)
{
#ifdef Markov
	return current + Constant::TAU * pow(Constant::e, current) * (secondDifference(previous, current, next) 
			+ pow(firstDifference(previous, next),2)) + Constant::a * Constant::TAU;
#endif // Markov
#ifdef Sherenk
	return current + Constant::TAU * Constant::a * ((3.0/2.0)*pow(current,(double)(-1.0/3.0))*(pow(firstDifference(previous,next),2))
		+pow(current,(double(2.0/3.0)))*secondDifference(previous,current,next)) + Constant::TAU * Constant::b * current; 
#endif // Sherenk
#ifdef Iskandar
	return current + Constant::a * Constant::TAU * ((-1) * pow(current, -2) * pow(firstDifference(previous,next),2) 
		+ pow(current,-1) * secondDifference(previous,current,next)) + Constant::TAU * Constant::b * current; 
#endif // Iskandar
}
void initNumericalMatrix (Matrix &matrix) {
	for (int i = 0; i < Constant::X_GRID_SIZE; ++i)
		matrix.set(0, i, accurateResultAt(Constant::X_LOWER_BOUND + i * Constant::H, Constant::T_LOWER_BOUND));
}
void setBounds4NumericalMatrix (Matrix &matrix) {
	for (int k = 0; k < Constant::T_GRID_SIZE; ++k) {
		matrix.set(k, 0, accurateResultAt(Constant::X_LOWER_BOUND, Constant::T_LOWER_BOUND + k * Constant::TAU));
		matrix.set(k, Constant::X_GRID_SIZE-1, accurateResultAt(Constant::X_UPPER_BOUND, Constant::T_LOWER_BOUND + k * Constant::TAU));
	}
}
void calculateNumericalResultExplicit (Matrix &matrix) {
	initNumericalMatrix(matrix);	
	setBounds4NumericalMatrix(matrix);

	double x = 0;

	for (int k = 0; k < Constant::T_GRID_SIZE - 1; ++k)
		for (int i = 1; i < Constant::X_GRID_SIZE - 1; ++i)
			matrix.set(k+1, i, calculateNextLayerPoint(matrix.get(k, i-1), matrix.get(k, i), matrix.get(k, i+1)));
}
